

#ifndef PF_MATH_H
#define PF_MATH_H

// no idea why, but doesn't link without that under win32 / bcc55:
#ifndef _MT
#define _MT
#endif
#include <math.h>
#include <errno.h>
#include <assert.h>
//   port abs issue on latest compiler?
#include <cstdlib>
#include "math_export.h"
#include <QRegExp>
#include "fparser.hh"

//#ifdef __GNUC__
//#define min(x,y) (x<y ? x : y)
//#define max(x,y) (x>y ? x : y)
//#endif

#define ARAD 57.29577951308232
#define PF_TOLERANCE 1.0e-10
#define PF_TOLERANCE_ANGLE 1.0e-8
#define M_PI       3.14159265358979323846
#define M_PI_2     1.57079632679489661923
typedef unsigned int uint;

/**
 * Math functions.
 */
class MATH_EXPORT PF_Math {
public:
    static int round(double v);
	static double pow(double x, double y);

    //static double abs(double v);
    //static int abs(int v);
    static double rad2deg(double a);
    static double deg2rad(double a);
    static double rad2gra(double a);
    static int findGCD(int a, int b);
    static bool isAngleBetween(double a,
                               double a1, double a2,
                               bool reversed);
    static double correctAngle(double a);
    static double getAngleDifference(double a1, double a2);
    static double makeAngleReadable(double angle, bool readable=true,
                                    bool* corrected=NULL);
    static bool isAngleReadable(double angle);
    static bool isSameDirection(double dir1, double dir2, double tol);
    static double eval(const QString& expr, double def=0.0);

    static bool cmpDouble(double v1, double v2, double tol=0.001);
  	
    /**
     * Evaluates a mathematical expression and returns the result.
     * If an error occured, ok will be set to false (if ok isn't NULL).
     */
	// Keep that in the header file for dynamic inclusion/exclusion.
    static double eval(const QString& expr, bool* ok) {
        if (expr.isEmpty()) {
            if (ok!=NULL) {
                *ok = false;
            }
            return 0.0;
        }

        FunctionParser fp;
        fp.AddConstant("pi", M_PI);

		// replace '14 3/4' with '14+3/4'
                QString s = expr;
		bool done;
		do {
			done = true;
                        int i = s.indexOf(QRegExp("[0-9]* [0-9]*/[0-9]*"));
			if (i!=-1) {
                                int i2 = s.indexOf(' ', i);
				if (i2!=-1) {
					s.replace(i2, 1, "+");
					done = false;
				}
			}
		} while (!done);

        int ret = fp.Parse(s.toLatin1().data(), "", true);

        if (ret>=0) {
            if (ok!=NULL) {
                *ok = false;
            }
            return 0.0;
        }

        if (ok!=NULL) {
            *ok = true;
        }

        return fp.Eval(NULL);
		return 0;
    }

    static QString doubleToString(double value, double prec);
    static QString doubleToString(double value, int prec);

    static void test();
};

#endif
